package jmetal.metaheuristics.nsgaII;

import java.util.Comparator;

import jmetal.core.Algorithm;
import jmetal.core.Operator;
import jmetal.core.Problem;
import jmetal.core.Solution;
import jmetal.core.SolutionSet;
import jmetal.util.JMException;
import jmetal.util.Ranking;
import jmetal.util.SingletonExtremePoint;
import jmetal.util.comparators.FitnessComparator;
import jmetal.util.dir.DirFitness;

public class FitnessNsga extends Algorithm{
	
	private static final long serialVersionUID = 6491179879661463650L;
	Operator mutationOperator;
	Operator crossoverOperator;
	Operator selectionOperator;
	int populationSize;
	int maxEvaluations;
	int evaluations;//当前evaluation 次数

	
	public FitnessNsga(Problem problem) {
		super(problem);
	}

	@Override
	public SolutionSet execute() throws JMException, ClassNotFoundException {

		initializeAlg();
		
		SolutionSet population = new SolutionSet(populationSize);
		initilizePopulation(population); 
//		int itr = 0;
		while(evaluations < maxEvaluations){
			double delta = 1.0-(double)(evaluations)/(double)(maxEvaluations);
			DirFitness popufitness = new DirFitness(population, populationSize,problem_);
			popufitness.assignFitness(0);
			
			SolutionSet offspringPopulation = generateOffspring(population);
			SolutionSet union = population.union(offspringPopulation);
			Ranking rank = new Ranking(union);
	        int remain = populationSize;
	        int index = 0;
	        SolutionSet front = null;
	        population.clear();
	        
	        front = rank.getSubfront(index);
	        while(remain>0&&remain>front.size()){
				for (int k = 0; k < front.size(); k++) {
					population.add(front.get(k));
				}
				remain = remain-front.size();
				index++;
				if(remain>0){
					front = rank.getSubfront(index);
				}
	        }
	        
	        if(remain>0){
	        	SolutionSet unionSet = population.union(front);
	        	DirFitness fitness = new DirFitness(unionSet, populationSize,problem_);
	        	delta = 1.0-(double)(evaluations/maxEvaluations);
	        	fitness.assignFitness(0);
	        	
	        	@SuppressWarnings("rawtypes")
				Comparator comparator = new FitnessComparator();
	        	
	        	front.sort(comparator);
	        	for(int i = 0;i<remain;i++){
	        		population.add(front.get(i));
	        	}
	        	remain = 0;
	        }
//	        System.out.println(delta);
//	        System.out.println(itr++);
		}
		SingletonExtremePoint.freePoint();
		Ranking ranking = new Ranking(population);
		return ranking.getSubfront(0);
	}


	
	private SolutionSet generateOffspring(SolutionSet population) throws JMException {
		SolutionSet offspringPopulation;
		offspringPopulation = new SolutionSet(populationSize);
		Solution[] parents = new Solution[2];
		for(int i=0;i<(populationSize/2);i++){
			if(evaluations<maxEvaluations){
				parents[0] = (Solution) selectionOperator.execute(population);
				parents[1] = (Solution) selectionOperator.execute(population);
				Solution[] offSpring = (Solution[]) crossoverOperator.execute(parents);
				mutationOperator.execute(offSpring[0]);
				mutationOperator.execute(offSpring[1]);
				problem_.evaluate(offSpring[0]);
				problem_.evaluateConstraints(offSpring[0]);
				problem_.evaluate(offSpring[1]);
				problem_.evaluateConstraints(offSpring[1]);
				offspringPopulation.add(offSpring[0]);
				offspringPopulation.add(offSpring[1]);
				evaluations += 2;
			}
		}
		return offspringPopulation;
	}

	private void initializeAlg() {
		// Read the parameters
		populationSize = ((Integer) getInputParameter("populationSize")).intValue();
		maxEvaluations = ((Integer) getInputParameter("maxEvaluations")).intValue();
		evaluations = 0;
		// Read the operators
		mutationOperator = operators_.get("mutation");
		crossoverOperator = operators_.get("crossover");
		selectionOperator = operators_.get("selection");
	}

	
	private void initilizePopulation(SolutionSet population)
			throws ClassNotFoundException, JMException {
		Solution newSolution;
		for (int i = 0; i < populationSize; i++) {
			newSolution = new Solution(problem_);
			problem_.evaluate(newSolution);
			problem_.evaluateConstraints(newSolution);
			evaluations++;
			population.add(newSolution);
		}
	}
	
}
